1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.codehaus.groovy.control;
20
21 import org.codehaus.groovy.control.customizers.CompilationCustomizer;
22 import org.codehaus.groovy.control.io.NullWriter;
23 import org.codehaus.groovy.control.messages.WarningMessage;
24
25 import java.io.File;
26 import java.io.PrintWriter;
27 import java.util.*;
28
29 /**
30 * Compilation control flags and coordination stuff.
31 *
32 * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
33 * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
34 * @author <a href="mailto:jim@pagesmiths.com">Jim White</a>
35 * @author <a href="mailto:cedric.champeau@gmail.com">Cedric Champeau</a>
36 */
37
38 public class CompilerConfiguration {
39
40 private static final String JDK5_CLASSNAME_CHECK = "java.lang.annotation.Annotation";
41
42 /** This (<code>"1.4"</code>) is the value for targetBytecode to compile for a JDK 1.4. **/
43 public static final String JDK4 = "1.4";
44 /** This (<code>"1.5"</code>) is the value for targetBytecode to compile for a JDK 1.5. **/
45 public static final String JDK5 = "1.5";
46 /** This (<code>"1.6"</code>) is the value for targetBytecode to compile for a JDK 1.6. **/
47 public static final String JDK6 = "1.6";
48 /** This (<code>"1.7"</code>) is the value for targetBytecode to compile for a JDK 1.7. **/
49 public static final String JDK7 = "1.7";
50 /** This (<code>"1.8"</code>) is the value for targetBytecode to compile for a JDK 1.8. **/
51 public static final String JDK8 = "1.8";
52
53 /** This (<code>"1.5"</code>) is the value for targetBytecode to compile for a JDK 1.5 or later JVM. **/
54 public static final String POST_JDK5 = JDK5; // for backwards compatibility
55
56 /** This (<code>"1.4"</code>) is the value for targetBytecode to compile for a JDK 1.4 JVM. **/
57 public static final String PRE_JDK5 = JDK4;
58
59 private static final String[] ALLOWED_JDKS = { JDK4, JDK5, JDK6, JDK7, JDK8 };
60
61 // Just call getVMVersion() once.
62 public static final String currentJVMVersion = getVMVersion();
63
64 // Static initializers are executed in text order,
65 // therefore we must do this one last!
66 /**
67 * A convenience for getting a default configuration. Do not modify it!
68 * See {@link #CompilerConfiguration(Properties)} for an example on how to
69 * make a suitable copy to modify. But if you're really starting from a
70 * default context, then you probably just want <code>new CompilerConfiguration()</code>.
71 */
72 public static final CompilerConfiguration DEFAULT = new CompilerConfiguration();
73
74 /**
75 * See {@link WarningMessage} for levels.
76 */
77 private int warningLevel;
78
79 /**
80 * Encoding for source files
81 */
82
83 private String sourceEncoding;
84 /**
85 * A <code>PrintWriter</code> for communicating with the user
86 */
87
88 private PrintWriter output;
89
90 /**
91 * Directory into which to write classes
92 */
93 private File targetDirectory;
94
95 /**
96 * Classpath for use during compilation
97 */
98 private LinkedList<String> classpath;
99
100 /**
101 * If true, the compiler should produce action information
102 */
103 private boolean verbose;
104
105 /**
106 * If true, debugging code should be activated
107 */
108 private boolean debug;
109
110 /**
111 * The number of non-fatal errors to allow before bailing
112 */
113 private int tolerance;
114
115 /**
116 * Base class name for scripts (must derive from Script)
117 */
118 private String scriptBaseClass;
119
120 private ParserPluginFactory pluginFactory;
121
122 /**
123 * extension used to find a groovy file
124 */
125 private String defaultScriptExtension;
126
127 /**
128 * extensions used to find a groovy files
129 */
130 private Set<String> scriptExtensions = new LinkedHashSet<String>();
131
132 /**
133 * if set to true recompilation is enabled
134 */
135 private boolean recompileGroovySource;
136
137 /**
138 * sets the minimum of time after a script can be recompiled.
139 */
140 private int minimumRecompilationInterval;
141
142 /**
143 * sets the bytecode version target
144 */
145 private String targetBytecode;
146
147 /**
148 * options for joint compilation (null by default == no joint compilation)
149 */
150 private Map<String, Object> jointCompilationOptions;
151
152 /**
153 * options for optimizations (empty map by default)
154 */
155 private Map<String, Boolean> optimizationOptions;
156
157 private List<CompilationCustomizer> compilationCustomizers = new LinkedList<CompilationCustomizer>();
158
159 /**
160 * Sets a list of global AST transformations which should not be loaded even if they are
161 * defined in META-INF/org.codehaus.groovy.transform.ASTTransformation files. By default,
162 * none is disabled.
163 */
164 private Set<String> disabledGlobalASTTransformations;
165
166 private BytecodeProcessor bytecodePostprocessor;
167
168 /**
169 * Sets the Flags to defaults.
170 */
171 public CompilerConfiguration() {
172 //
173 // Set in safe defaults
174
175 setWarningLevel(WarningMessage.LIKELY_ERRORS);
176 setOutput(null);
177 setTargetDirectory((File) null);
178 setClasspath("");
179 setVerbose(false);
180 setDebug(false);
181 setTolerance(10);
182 setScriptBaseClass(null);
183 setRecompileGroovySource(false);
184 setMinimumRecompilationInterval(100);
185 // Target bytecode
186 String targetByteCode = null;
187 try {
188 targetByteCode = System.getProperty("groovy.target.bytecode", targetByteCode);
189 } catch (Exception e) {
190 // IGNORE
191 }
192 if(targetByteCode != null) {
193 setTargetBytecode(targetByteCode);
194 } else {
195 setTargetBytecode(getVMVersion());
196 }
197 String tmpDefaultScriptExtension = null;
198 try {
199 tmpDefaultScriptExtension = System.getProperty("groovy.default.scriptExtension");
200 } catch (Exception e) {
201 // IGNORE
202 }
203 if(tmpDefaultScriptExtension != null) {
204 setDefaultScriptExtension(tmpDefaultScriptExtension);
205 } else {
206 setDefaultScriptExtension(".groovy");
207 }
208
209 //
210 // Source file encoding
211 String encoding = null;
212 try {
213 encoding = System.getProperty("file.encoding", "US-ASCII");
214 } catch (Exception e) {
215 // IGNORE
216 }
217 try {
218 encoding = System.getProperty("groovy.source.encoding", encoding);
219 } catch (Exception e) {
220 // IGNORE
221 }
222 setSourceEncoding(encoding);
223
224 try {
225 setOutput(new PrintWriter(System.err));
226 } catch (Exception e) {
227 // IGNORE
228 }
229
230 try {
231 String target = System.getProperty("groovy.target.directory");
232 if (target != null) {
233 setTargetDirectory(target);
234 }
235 } catch (Exception e) {
236 // IGNORE
237 }
238
239 boolean indy = false;
240 try {
241 indy = Boolean.getBoolean("groovy.target.indy");
242 } catch (Exception e) {
243 // IGNORE
244 }
245 if (DEFAULT!=null && Boolean.TRUE.equals(DEFAULT.getOptimizationOptions().get("indy"))) {
246 indy = true;
247 }
248 Map options = new HashMap<String,Boolean>(3);
249 if (indy) {
250 options.put("indy", Boolean.TRUE);
251 }
252 setOptimizationOptions(options);
253 }
254
255 /**
256 * Copy constructor. Use this if you have a mostly correct configuration
257 * for your compilation but you want to make a some changes programatically.
258 * An important reason to prefer this approach is that your code will most
259 * likely be forward compatible with future changes to this configuration API.
260 * <p>
261 * An example of this copy constructor at work:
262 * <pre>
263 * // In all likelihood there is already a configuration in your code's context
264 * // for you to copy, but for the sake of this example we'll use the global default.
265 * CompilerConfiguration myConfiguration = new CompilerConfiguration(CompilerConfiguration.DEFAULT);
266 * myConfiguration.setDebug(true);
267 *</pre>
268 *
269 * @param configuration The configuration to copy.
270 */
271 public CompilerConfiguration(CompilerConfiguration configuration) {
272 setWarningLevel(configuration.getWarningLevel());
273 setOutput(configuration.getOutput());
274 setTargetDirectory(configuration.getTargetDirectory());
275 setClasspathList(new LinkedList<String>(configuration.getClasspath()));
276 setVerbose(configuration.getVerbose());
277 setDebug(configuration.getDebug());
278 setTolerance(configuration.getTolerance());
279 setScriptBaseClass(configuration.getScriptBaseClass());
280 setRecompileGroovySource(configuration.getRecompileGroovySource());
281 setMinimumRecompilationInterval(configuration.getMinimumRecompilationInterval());
282 setTargetBytecode(configuration.getTargetBytecode());
283 setDefaultScriptExtension(configuration.getDefaultScriptExtension());
284 setSourceEncoding(configuration.getSourceEncoding());
285 setOutput(configuration.getOutput());
286 setTargetDirectory(configuration.getTargetDirectory());
287 Map<String, Object> jointCompilationOptions = configuration.getJointCompilationOptions();
288 if (jointCompilationOptions != null) {
289 jointCompilationOptions = new HashMap<String, Object>(jointCompilationOptions);
290 }
291 setJointCompilationOptions(jointCompilationOptions);
292 setPluginFactory(configuration.getPluginFactory());
293 setScriptExtensions(configuration.getScriptExtensions());
294 setOptimizationOptions(new HashMap<String, Boolean>(configuration.getOptimizationOptions()));
295 }
296
297 /**
298 * Sets the Flags to the specified configuration, with defaults
299 * for those not supplied.
300 * Note that those "defaults" here do <em>not</em> include checking the
301 * settings in {@link System#getProperties()} in general, only file.encoding,
302 * groovy.target.directory and groovy.source.encoding are.
303 * <p>
304 * If you want to set a few flags but keep Groovy's default
305 * configuration behavior then be sure to make your settings in
306 * a Properties that is backed by <code>System.getProperties()</code> (which
307 * is done using this constructor). That might be done like this:
308 * <pre>
309 * Properties myProperties = new Properties(System.getProperties());
310 * myProperties.setProperty("groovy.output.debug", "true");
311 * myConfiguration = new CompilerConfiguration(myProperties);
312 * </pre>
313 * And you also have to contend with a possible SecurityException when
314 * getting the system properties (See {@link java.lang.System#getProperties()}).
315 * A safer approach would be to copy a default
316 * CompilerConfiguration and make your changes there using the setter:
317 * <pre>
318 * // In all likelihood there is already a configuration for you to copy,
319 * // but for the sake of this example we'll use the global default.
320 * CompilerConfiguration myConfiguration = new CompilerConfiguration(CompilerConfiguration.DEFAULT);
321 * myConfiguration.setDebug(true);
322 * </pre>
323 * Another reason to use the copy constructor rather than this one is that you
324 * must call {@link #setOutput}. Calling <code>setOutput(null)</code> is valid and will
325 * set up a <code>PrintWriter</code> to a bit bucket. The copy constructor will of course set
326 * the same one as the original.
327 * <p>
328 * <table summary="Groovy Compiler Configuration Properties">
329 * <tr>
330 * <th>Property Key</th><th>Get/Set Property Name</th>
331 * </tr>
332 * <tr>
333 * <td><code>"groovy.warnings"</code></td><td>{@link #getWarningLevel}</td></tr>
334 * <tr><td><code>"groovy.source.encoding"</code></td><td>{@link #getSourceEncoding}</td></tr>
335 * <tr><td><code>"groovy.target.directory"</code></td><td>{@link #getTargetDirectory}</td></tr>
336 * <tr><td><code>"groovy.target.bytecode"</code></td><td>{@link #getTargetBytecode}</td></tr>
337 * <tr><td><code>"groovy.classpath"</code></td><td>{@link #getClasspath}</td></tr>
338 * <tr><td><code>"groovy.output.verbose"</code></td><td>{@link #getVerbose}</td></tr>
339 * <tr><td><code>"groovy.output.debug"</code></td><td>{@link #getDebug}</td></tr>
340 * <tr><td><code>"groovy.errors.tolerance"</code></td><td>{@link #getTolerance}</td></tr>
341 * <tr><td><code>"groovy.script.extension"</code></td><td>{@link #getDefaultScriptExtension}</td></tr>
342 * <tr><td><code>"groovy.script.base"</code></td><td>{@link #getScriptBaseClass}</td></tr>
343 * <tr><td><code>"groovy.recompile"</code></td><td>{@link #getRecompileGroovySource}</td></tr>
344 * <tr><td><code>"groovy.recompile.minimumInterval"</code></td><td>{@link #getMinimumRecompilationInterval}</td></tr>
345 * <tr><td>
346 * </tr>
347 * </table>
348 *
349 * @param configuration The properties to get flag values from.
350 */
351 public CompilerConfiguration(Properties configuration) throws ConfigurationException {
352 this();
353 configure(configuration);
354 }
355
356 /**
357 * Checks if the specified bytecode version string represents a JDK 1.5+ compatible
358 * bytecode version.
359 * @param bytecodeVersion the bytecode version string (1.4, 1.5, 1.6, 1.7 or 1.8)
360 * @return true if the bytecode version is JDK 1.5+
361 */
362 public static boolean isPostJDK5(String bytecodeVersion) {
363 return JDK5.equals(bytecodeVersion)
364 || JDK6.equals(bytecodeVersion)
365 || JDK7.equals(bytecodeVersion)
366 || JDK8.equals(bytecodeVersion);
367 }
368
369 /**
370 * Checks if the specified bytecode version string represents a JDK 1.7+ compatible
371 * bytecode version.
372 * @param bytecodeVersion the bytecode version string (1.4, 1.5, 1.6, 1.7 or 1.8)
373 * @return true if the bytecode version is JDK 1.7+
374 */
375 public static boolean isPostJDK7(String bytecodeVersion) {
376 return JDK7.equals(bytecodeVersion)
377 || JDK8.equals(bytecodeVersion);
378 }
379
380 /**
381 * Method to configure a this CompilerConfiguration by using Properties.
382 * For a list of available properties look at {link {@link #CompilerConfiguration(Properties)}.
383 * @param configuration The properties to get flag values from.
384 */
385 public void configure(Properties configuration) throws ConfigurationException {
386 String text = null;
387 int numeric = 0;
388
389 //
390 // Warning level
391
392 numeric = getWarningLevel();
393 try {
394 text = configuration.getProperty("groovy.warnings", "likely errors");
395 numeric = Integer.parseInt(text);
396 } catch (NumberFormatException e) {
397 text = text.toLowerCase();
398 if (text.equals("none")) {
399 numeric = WarningMessage.NONE;
400 }
401 else if (text.startsWith("likely")) {
402 numeric = WarningMessage.LIKELY_ERRORS;
403 }
404 else if (text.startsWith("possible")) {
405 numeric = WarningMessage.POSSIBLE_ERRORS;
406 }
407 else if (text.startsWith("paranoia")) {
408 numeric = WarningMessage.PARANOIA;
409 }
410 else {
411 throw new ConfigurationException("unrecognized groovy.warnings: " + text);
412 }
413 }
414 setWarningLevel(numeric);
415
416 //
417 // Source file encoding
418 //
419 text = configuration.getProperty("groovy.source.encoding");
420 if (text == null) {
421 text = configuration.getProperty("file.encoding", "US-ASCII");
422 }
423 setSourceEncoding(text);
424
425 //
426 // Target directory for classes
427 //
428 text = configuration.getProperty("groovy.target.directory");
429 if (text != null) setTargetDirectory(text);
430
431 text = configuration.getProperty("groovy.target.bytecode");
432 if (text != null) setTargetBytecode(text);
433
434 //
435 // Classpath
436 //
437 text = configuration.getProperty("groovy.classpath");
438 if (text != null) setClasspath(text);
439
440 //
441 // Verbosity
442 //
443 text = configuration.getProperty("groovy.output.verbose");
444 if (text != null && text.equalsIgnoreCase("true")) setVerbose(true);
445
446 //
447 // Debugging
448 //
449 text = configuration.getProperty("groovy.output.debug");
450 if (text != null && text.equalsIgnoreCase("true")) setDebug(true);
451
452 //
453 // Tolerance
454 //
455 numeric = 10;
456 try {
457 text = configuration.getProperty("groovy.errors.tolerance", "10");
458 numeric = Integer.parseInt(text);
459 } catch (NumberFormatException e) {
460 throw new ConfigurationException(e);
461 }
462 setTolerance(numeric);
463
464 //
465 // Script Base Class
466 //
467 text = configuration.getProperty("groovy.script.base");
468 if (text!=null) setScriptBaseClass(text);
469
470 //
471 // recompilation options
472 //
473 text = configuration.getProperty("groovy.recompile");
474 if (text != null) {
475 setRecompileGroovySource(text.equalsIgnoreCase("true"));
476 }
477
478 numeric = 100;
479 try {
480 text = configuration.getProperty("groovy.recompile.minimumIntervall");
481 if (text==null) text = configuration.getProperty("groovy.recompile.minimumInterval");
482 if (text!=null) {
483 numeric = Integer.parseInt(text);
484 } else {
485 numeric = 100;
486 }
487 } catch (NumberFormatException e) {
488 throw new ConfigurationException(e);
489 }
490 setMinimumRecompilationInterval(numeric);
491
492 // disabled global AST transformations
493 text = configuration.getProperty("groovy.disabled.global.ast.transformations");
494 if (text!=null) {
495 String[] classNames = text.split(",\\s*}");
496 Set<String> blacklist = new HashSet<String>(Arrays.asList(classNames));
497 setDisabledGlobalASTTransformations(blacklist);
498 }
499 }
500
501 /**
502 * Gets the currently configured warning level. See WarningMessage
503 * for level details.
504 */
505 public int getWarningLevel() {
506 return this.warningLevel;
507 }
508
509 /**
510 * Sets the warning level. See WarningMessage for level details.
511 */
512 public void setWarningLevel(int level) {
513 if (level < WarningMessage.NONE || level > WarningMessage.PARANOIA) {
514 this.warningLevel = WarningMessage.LIKELY_ERRORS;
515 }
516 else {
517 this.warningLevel = level;
518 }
519 }
520
521 /**
522 * Gets the currently configured source file encoding.
523 */
524 public String getSourceEncoding() {
525 return this.sourceEncoding;
526 }
527
528 /**
529 * Sets the encoding to be used when reading source files.
530 */
531 public void setSourceEncoding(String encoding) {
532 if (encoding == null) encoding = "US-ASCII";
533 this.sourceEncoding = encoding;
534 }
535
536 /**
537 * Gets the currently configured output writer.
538 */
539 public PrintWriter getOutput() {
540 return this.output;
541 }
542
543 /**
544 * Sets the output writer.
545 */
546 public void setOutput(PrintWriter output) {
547 if (output == null) {
548 this.output = new PrintWriter(NullWriter.DEFAULT);
549 }
550 else {
551 this.output = output;
552 }
553 }
554
555 /**
556 * Gets the target directory for writing classes.
557 */
558 public File getTargetDirectory() {
559 return this.targetDirectory;
560 }
561
562 /**
563 * Sets the target directory.
564 */
565 public void setTargetDirectory(String directory) {
566 if (directory != null && directory.length() > 0) {
567 this.targetDirectory = new File(directory);
568 } else {
569 this.targetDirectory = null;
570 }
571 }
572
573 /**
574 * Sets the target directory.
575 */
576 public void setTargetDirectory(File directory) {
577 this.targetDirectory = directory;
578 }
579
580 /**
581 * @return the classpath
582 */
583 public List<String> getClasspath() {
584 return this.classpath;
585 }
586
587 /**
588 * Sets the classpath.
589 */
590 public void setClasspath(String classpath) {
591 this.classpath = new LinkedList<String>();
592 StringTokenizer tokenizer = new StringTokenizer(classpath, File.pathSeparator);
593 while (tokenizer.hasMoreTokens()) {
594 this.classpath.add(tokenizer.nextToken());
595 }
596 }
597
598 /**
599 * sets the classpath using a list of Strings
600 * @param parts list of strings containing the classpath parts
601 */
602 public void setClasspathList(List<String> parts) {
603 this.classpath = new LinkedList<String>(parts);
604 }
605
606 /**
607 * Returns true if verbose operation has been requested.
608 */
609 public boolean getVerbose() {
610 return this.verbose;
611 }
612
613 /**
614 * Turns verbose operation on or off.
615 */
616 public void setVerbose(boolean verbose) {
617 this.verbose = verbose;
618 }
619
620 /**
621 * Returns true if debugging operation has been requested.
622 */
623 public boolean getDebug() {
624 return this.debug;
625 }
626
627 /**
628 * Turns debugging operation on or off.
629 */
630 public void setDebug(boolean debug) {
631 this.debug = debug;
632 }
633
634 /**
635 * Returns the requested error tolerance.
636 */
637 public int getTolerance() {
638 return this.tolerance;
639 }
640
641 /**
642 * Sets the error tolerance, which is the number of
643 * non-fatal errors (per unit) that should be tolerated before
644 * compilation is aborted.
645 */
646 public void setTolerance(int tolerance) {
647 this.tolerance = tolerance;
648 }
649
650 /**
651 * Gets the name of the base class for scripts. It must be a subclass
652 * of Script.
653 */
654 public String getScriptBaseClass() {
655 return this.scriptBaseClass;
656 }
657
658 /**
659 * Sets the name of the base class for scripts. It must be a subclass
660 * of Script.
661 */
662 public void setScriptBaseClass(String scriptBaseClass) {
663 this.scriptBaseClass = scriptBaseClass;
664 }
665
666 public ParserPluginFactory getPluginFactory() {
667 if (pluginFactory == null) {
668 pluginFactory = ParserPluginFactory.newInstance(true);
669 }
670 return pluginFactory;
671 }
672
673 public void setPluginFactory(ParserPluginFactory pluginFactory) {
674 this.pluginFactory = pluginFactory;
675 }
676
677 public void setScriptExtensions(Set<String> scriptExtensions) {
678 if(scriptExtensions == null) scriptExtensions = new LinkedHashSet<String>();
679 this.scriptExtensions = scriptExtensions;
680 }
681
682 public Set<String> getScriptExtensions() {
683 if(scriptExtensions == null || scriptExtensions.isEmpty()) {
684 /*
685 * this happens
686 * * when groovyc calls FileSystemCompiler in forked mode, or
687 * * when FileSystemCompiler is run from the command line directly, or
688 * * when groovy was not started using groovyc or FileSystemCompiler either
689 */
690 scriptExtensions = SourceExtensionHandler.getRegisteredExtensions(
691 this.getClass().getClassLoader());
692 }
693 return scriptExtensions;
694 }
695
696 public String getDefaultScriptExtension() {
697 return defaultScriptExtension;
698 }
699
700
701 public void setDefaultScriptExtension(String defaultScriptExtension) {
702 this.defaultScriptExtension = defaultScriptExtension;
703 }
704
705 public void setRecompileGroovySource(boolean recompile) {
706 recompileGroovySource = recompile;
707 }
708
709 public boolean getRecompileGroovySource(){
710 return recompileGroovySource;
711 }
712
713 public void setMinimumRecompilationInterval(int time) {
714 minimumRecompilationInterval = Math.max(0,time);
715 }
716
717 public int getMinimumRecompilationInterval() {
718 return minimumRecompilationInterval;
719 }
720
721 /**
722 * Allow setting the bytecode compatibility. The parameter can take
723 * one of the values <tt>1.7</tt>, <tt>1.6</tt>, <tt>1.5</tt> or <tt>1.4</tt>.
724 * If wrong parameter then the value will default to VM determined version.
725 *
726 * @param version the bytecode compatibility mode
727 */
728 public void setTargetBytecode(String version) {
729 for (String allowedJdk : ALLOWED_JDKS) {
730 if (allowedJdk.equals(version)) {
731 this.targetBytecode = version;
732 }
733 }
734 }
735
736 /**
737 * Retrieves the compiler bytecode compatibility mode.
738 *
739 * @return bytecode compatibility mode. Can be either <tt>1.5</tt> or <tt>1.4</tt>.
740 */
741 public String getTargetBytecode() {
742 return this.targetBytecode;
743 }
744
745 private static String getVMVersion() {
746 try {
747 Class.forName(JDK5_CLASSNAME_CHECK);
748 return POST_JDK5;
749 } catch(Exception ex) {
750 // IGNORE
751 }
752 return PRE_JDK5;
753 }
754
755 /**
756 * Gets the joint compilation options for this configuration.
757 * @return the options
758 */
759 public Map<String, Object> getJointCompilationOptions() {
760 return jointCompilationOptions;
761 }
762
763 /**
764 * Sets the joint compilation options for this configuration.
765 * Using null will disable joint compilation.
766 * @param options the options
767 */
768 public void setJointCompilationOptions(Map<String, Object> options) {
769 jointCompilationOptions = options;
770 }
771
772 /**
773 * Gets the optimization options for this configuration.
774 * @return the options (always not null)
775 */
776 public Map<String, Boolean> getOptimizationOptions() {
777 return optimizationOptions;
778 }
779
780 /**
781 * Sets the optimization options for this configuration.
782 * No entry or a true for that entry means to enable that optimization,
783 * a false means the optimization is disabled.
784 * Valid keys are "all" and "int".
785 * @param options the options.
786 * @throws IllegalArgumentException if the options are null
787 */
788 public void setOptimizationOptions(Map<String, Boolean> options) {
789 if (options==null) throw new IllegalArgumentException("provided option map must not be null");
790 optimizationOptions = options;
791 }
792
793 /**
794 * Adds compilation customizers to the compilation process. A compilation customizer is a class node
795 * operation which performs various operations going from adding imports to access control.
796 * @param customizers the list of customizers to be added
797 * @return this configuration instance
798 */
799 public CompilerConfiguration addCompilationCustomizers(CompilationCustomizer... customizers) {
800 if (customizers==null) throw new IllegalArgumentException("provided customizers list must not be null");
801 compilationCustomizers.addAll(Arrays.asList(customizers));
802 return this;
803 }
804
805 /**
806 * Returns the list of compilation customizers.
807 * @return the customizers (always not null)
808 */
809 public List<CompilationCustomizer> getCompilationCustomizers() {
810 return compilationCustomizers;
811 }
812
813 /**
814 * Returns the list of disabled global AST transformation class names.
815 * @return a list of global AST transformation fully qualified class names
816 */
817 public Set<String> getDisabledGlobalASTTransformations() {
818 return disabledGlobalASTTransformations;
819 }
820
821 /**
822 * Disables global AST transformations. In order to avoid class loading side effects, it is not recommended
823 * to use MyASTTransformation.class.getName() by directly use the class name as a string. Disabled AST transformations
824 * only apply to automatically loaded global AST transformations, that is to say transformations defined in a
825 * META-INF/org.codehaus.groovy.transform.ASTTransformation file. If you explicitly add a global AST transformation
826 * in your compilation process, for example using the {@link org.codehaus.groovy.control.customizers.ASTTransformationCustomizer} or
827 * using a {@link org.codehaus.groovy.control.CompilationUnit.PrimaryClassNodeOperation}, then nothing will prevent
828 * the transformation from being loaded.
829 * @param disabledGlobalASTTransformations a set of fully qualified class names of global AST transformations
830 * which should not be loaded.
831 */
832 public void setDisabledGlobalASTTransformations(final Set<String> disabledGlobalASTTransformations) {
833 this.disabledGlobalASTTransformations = disabledGlobalASTTransformations;
834 }
835
836 public BytecodeProcessor getBytecodePostprocessor() {
837 return bytecodePostprocessor;
838 }
839
840 public void setBytecodePostprocessor(final BytecodeProcessor bytecodePostprocessor) {
841 this.bytecodePostprocessor = bytecodePostprocessor;
842 }
843 }